﻿(($, window, document) => {
    if (!$) {
        return console.error('in datetimepicker.kmhealth.js, $ is null');
    }

    $.fn.extend({
        datetimepicker(options = {}) {
            $(() => {

                let {
                    className = '',
                    initDate,
                    startDate,
                    endDate,

                    dateClickCondition = () => true,
                    monthClickCondition = () => true,
                    yearClickCondition = () => true,

                    format = 'yyyy/MM/dd'
                } = options;

                let displayDate = initDate;
                let selectDate = initDate;
                let template = table.template({
                    className
                });

                let button = $(this);
                let picker = $(template.main).appendTo("body");

                function formatDate(date) {

                    let unitList = format.split(/[ymMd]*/);

                    //去除正则所匹配的起始结尾空格
                    unitList.splice(0, 1);

                    let ym = unitList[0];
                    let md = unitList[1];
                    let year = date.getFullYear() + '';
                    let month = date.getMonth() + 1;
                    let day = date.getDate();

                    month = (month < 10 ? '0' : '') + month;
                    day = (day < 10 ? '0' : '') + day;

                    let y = /[y]+/g.exec(format)[0] || 'yyyy';
                    let M = /[M]+/g.exec(format)[0] || 'MM';
                    let d = /[d]+/g.exec(format)[0] || 'dd';

                    year = year.substr(4 - y.length, 4);
                    month = month.substr(2 - M.length, 4);
                    day = day.substr(2 - d.length, 4);

                    return `${year}${ym}${month}${md}${day}`;
                }

                if (initDate instanceof Date) {
                    button.val(formatDate(initDate));
                }

                button.on('click', (e) => {
                    //e.preventDefault();
                    //e.stopPropagation();

                    displayDate = selectDate || new Date();

                    //展开与隐藏时间控件
                    let offset = button.offset();
                    let showDate = displayDate;

                    picker.css({
                        left: offset.left,
                        top: offset.top + button.outerHeight()
                    }).toggleClass('on');

                    picker.width(button.outerWidth());

                    if (picker.hasClass('on')) {
                        $('.select-date,.select-month,.select-year')
                            .hide()
                            .filter('.select-date')
                            .show();

                        createDatePage(showDate);

                        if (selectDate instanceof Date) {
                            picker.find('.select-date .datetime-tr td').each((index, elm) => {
                                let $elm = $(elm);
                                let { year, month, date } = $elm.data('date');
                                if (year === selectDate.getFullYear() &&
                                    month === selectDate.getMonth() &&
                                    date === selectDate.getDate()) {
                                    $elm.addClass('on');
                                }
                            });
                        }
                    }
                });

                $(document.body).on('click', (e) => {
                    let target = $(e.target);
                    if (picker.is(target) || picker.find(target).length > 0 || button.is(target) || button.find(target).length > 0) {
                        return;
                    }

                    picker.removeClass('on');
                });

                //控件事件
                picker.find('.dtp-left').on('click', (e) => {
                    let target = $(e.currentTarget);
                    let selectDiv = target.parents('.select-date,.select-month,.select-year');

                    if (selectDiv.hasClass('select-date')) {
                        let showDate = new Date(displayDate.getFullYear(), displayDate.getMonth() - 1, 1);

                        if (startDate instanceof Date) {
                            let displayCurrentDate = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1);
                            let start = new Date(startDate);
                            start.setDate(2);

                            if (displayCurrentDate < start) {
                                return;
                            }
                        }

                        displayDate = showDate;

                        createDatePage(showDate);
                        button.trigger('date.left.click');

                        button.trigger('date.general', [picker.find('.select-date table')]);
                    } else if (selectDiv.hasClass('select-month')) {
                        let year = displayDate.getFullYear() - 1;

                        if (startDate instanceof Date) {

                            if (year < startDate.getFullYear()) {
                                return;
                            }
                        }

                        displayDate.setFullYear(year);
                        createMonthPage(displayDate);
                        selectDiv.find('.year').text(year);
                    } else if (selectDiv.hasClass('select-year')) {
                        let year = displayDate.getFullYear() - 10;

                        if (startDate instanceof Date) {
                            let displayCurrentDate = new Date(year, displayDate.getMonth(), 1);
                            let start = new Date(startDate);
                            start.setDate(2);

                            if (displayCurrentDate < start) {
                                return;
                            }
                        }

                        displayDate.setFullYear(year);
                        createAllYearPage(displayDate);
                    }
                });

                picker.find('table').on('click', '.datetime-tr a', (e) => {
                    let target = $(e.currentTarget);
                    let selectDiv = target.parents('.select-date,.select-month,.select-year');
                    let td = target.parents('td');

                    if (td.hasClass('not-active')) {
                        return;
                    }

                    if (selectDiv.hasClass('select-date')) {
                        let { date, month, year } = td.data('date');
                        let dataDate = new Date(year, month, date);

                        if (!dateClickCondition(target.parents('td'))) {
                            return;
                        }

                        button.val(formatDate(dataDate));
                        picker.removeClass('on');

                        displayDate = new Date(dataDate);
                        selectDate = new Date(dataDate);

                        button.trigger('date.change', [target]);
                    } else if (selectDiv.hasClass('select-month')) {

                        if (!monthClickCondition(target.parents('td'))) {
                            return;
                        }

                        displayDate.setMonth(td.data('month'));
                        selectDiv
                            .hide()
                            .next()
                            .show();

                        createDatePage(displayDate);
                        selectDate = new Date(displayDate);
                        button.trigger('month.change', [target]);
                    } else if (selectDiv.hasClass('select-year')) {

                        if (!yearClickCondition(target.parents('td'))) {
                            return;
                        }

                        displayDate.setYear(td.data('year'));

                        selectDiv
                            .hide()
                            .next()
                            .show();

                        createMonthPage(displayDate);
                        selectDate = new Date(displayDate);
                        button.trigger('year.change', [target]);
                    }
                });

                picker.find('.dtp-right').on('click', (e) => {
                    let target = $(e.currentTarget);
                    let selectDiv = target.parents('.select-date,.select-month,.select-year');

                    if (selectDiv.hasClass('select-date')) {
                        let showDate = new Date(displayDate.getFullYear(), displayDate.getMonth() + 1, 1);

                        if (endDate instanceof Date) {
                            let displayCurrentDate = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1);
                            let end = new Date(endDate);

                            end.setMonth(end.getMonth() - 1);
                            end.setDate(1);

                            if (displayCurrentDate > end) {
                                return;
                            }
                        }

                        displayDate = showDate;

                        createDatePage(showDate);
                        button.trigger('date.right.click');

                        button.trigger('date.general', [picker.find('.select-date table')]);
                    } else if (selectDiv.hasClass('select-month')) {
                        let year = displayDate.getFullYear() + 1;

                        if (endDate instanceof Date) {
                            let endYear = endDate.getFullYear();
                            if (year > endYear) {
                                return;
                            }
                        }

                        displayDate.setFullYear(year);
                        selectDiv.find('.year').text(year);
                        createMonthPage(displayDate);
                    } else if (selectDiv.hasClass('select-year')) {
                        let year = displayDate.getFullYear() + 10;

                        if (endDate instanceof Date) {
                            let displayCurrentDate = new Date(year, displayDate.getMonth(), 1);
                            let end = new Date(endDate);

                            end.setMonth(end.getMonth() - 1);
                            end.setDate(1);

                            if (displayCurrentDate > end) {
                                return;
                            }
                        }

                        displayDate.setFullYear(year);
                        createAllYearPage(displayDate);
                        button.trigger('year.change', [target]);
                    }
                });

                picker.find('.year').on('click', (e) => {
                    let target = $(e.currentTarget);
                    let selectDiv = target.parents('.select-date,.select-month,.select-year');


                    $('.select-date,.select-month,.select-year').hide();

                    if (selectDiv.hasClass('select-date')) {
                        let selectMonth = $('.select-month').show();
                        let month = displayDate.getMonth();

                        createMonthPage(displayDate);

                        selectMonth.find('table .datetime-tr td').each((index, elem) => {
                            let $elem = $(elem);

                            if ($elem.data('month') === month) {
                                $elem.addClass('on');
                            }
                        });
                    } else if (selectDiv.hasClass('select-month')) {
                        let selectYear = $('.select-year').show();
                        let year = displayDate.getFullYear();

                        createAllYearPage(displayDate);

                        selectYear.find('table .datetime-tr td').each((index, elem) => {
                            let $elem = $(elem);
                            let elmYear = $elem.data('year');

                            if (elmYear === year) {
                                $elem.addClass('on');
                            }
                        });
                    } else if (selectDiv.hasClass('select-year')) {
                        $('.select-year').show();
                        return;
                    }
                });

                $(window).on('resize', () => {
                    let offset = button.offset();
                    picker.width(button.outerWidth());

                    picker.css({
                        left: offset.left,
                        top: offset.top + button.outerHeight()
                    });


                });

                function createDatePage(showDate) {
                    picker.find('.select-date .datetime-tr').remove();

                    let currentDateGroup = new Date(showDate.getFullYear(), showDate.getMonth() + 1, 0);
                    let index = (new Date(currentDateGroup.getFullYear(), currentDateGroup.getMonth(), 1)).getDay();
                    let prevDatetime = new Date(showDate.getFullYear(), showDate.getMonth(), 0);
                    let nextDatetime = new Date(showDate.getFullYear(), showDate.getMonth() + 2, 0);
                    let prevDate = prevDatetime.getDate();
                    let dateArray = [];

                    if (index > 0) {
                        for (let i = 1; i <= index; i++) {
                            let num = index - i;

                            dateArray.push({
                                isCurrent: false,
                                date: prevDate - num,
                                month: prevDatetime.getMonth(),
                                year: prevDatetime.getFullYear()
                            });
                        }
                    }

                    for (let i = 1; i <= currentDateGroup.getDate(); i++) {
                        dateArray.push({
                            isCurrent: true,
                            date: i,
                            month: currentDateGroup.getMonth(),
                            year: currentDateGroup.getFullYear()
                        });
                    }

                    let length = (35 - dateArray.length);
                    length = length <= 0 ? 42 - dateArray.length : length;

                    for (let i = 1; i <= length; i++) {
                        dateArray.push({
                            isCurrent: false,
                            date: i,
                            month: nextDatetime.getMonth(),
                            year: nextDatetime.getFullYear()
                        });
                    }

                    let temp = [].concat(dateArray);
                    dateArray.splice(0, dateArray.length);

                    while (temp.length > 0) {
                        dateArray.push(temp.splice(0, 7));
                    }

                    let selectDateList = dateArray.map(x => {
                        let tr = $(template.tr());
                        tr.append(
                            x.map(n => {
                                let elmDate = new Date(n.year, n.month, n.date);
                                let $elm = $(template.td(n.date))
                                    .addClass(n.isCurrent ? '' : 'graw')
                                    .data('date', n);

                                if (startDate instanceof Date) {
                                    if (elmDate < startDate) {
                                        $elm.addClass('not-active');
                                    }
                                }

                                if (endDate instanceof Date) {
                                    if (elmDate > endDate) {
                                        $elm.addClass('not-active');
                                    }
                                }

                                return $elm;
                            })
                        );

                        return tr;
                    });

                    let month = (currentDateGroup.getMonth() + 1);

                    picker.find('.select-date table').append(selectDateList);
                    picker.find('.select-date .year').text(`${currentDateGroup.getFullYear()}-${(month >= 10 ? '' : '0') + month}`);

                    button.trigger('date.general', [picker.find('.select-date table')]);
                }

                function createMonthPage(showDate) {
                    let year = showDate.getFullYear();

                    picker.find('.select-month .datetime-tr').remove();

                    let monthList = [
                        [1, 2, 3, 4],
                        [5, 6, 7, 8],
                        [9, 10, 11, 12]
                    ];

                    let group = monthList.map(x => $(template.tr()).append(
                        x.map(n => {
                            let td = $(template.td((n < 10 ? '0' : '') + n));
                            let month = n - 1;
                            if (startDate instanceof Date && year <= startDate.getFullYear()) {

                                if (month < startDate.getMonth()) {
                                    td.addClass('not-active');
                                }
                            }

                            if (endDate instanceof Date && year >= endDate.getFullYear()) {

                                if (month > endDate.getMonth()) {
                                    td.addClass('not-active');
                                }
                            }

                            td.data('month', month);

                            return td;
                        })
                    ));

                    picker.find('.select-month table').append(group).removeData('year');
                    picker.find('.select-month .year').text(showDate.getFullYear());

                    button.trigger('month.general', [picker.find('.select-month table')]);
                }

                function createAllYearPage(showDate) {
                    picker.find('.select-year .datetime-tr').remove();

                    let year = showDate.getFullYear();
                    let sub = parseInt(year / 10) * 10;
                    let list = [sub - 1];
                    for (var i = 0; i < 11; i++) {
                        list.push(sub + i);
                    }

                    let temp = [].concat(list);
                    list = [];
                    while (temp.length > 0) {
                        list.push(temp.splice(0, 4));
                    }

                    let trGroup = list.map(x => $(template.tr()).append(
                        x.map(n => {
                            let td = $(template.td(n)).data('year', n);


                            if (startDate instanceof Date && endDate instanceof Date) {
                                let startYear = startDate.getFullYear();
                                let endYear = endDate.getFullYear();

                                if (n < startYear || n > endYear) {
                                    td.addClass('not-active');
                                }
                            }

                            return td;
                        })
                    ));


                    picker.find('.select-year table').append(trGroup);
                    picker.find('.select-year .year').text(`${sub - 1}-${sub + 10}`);

                    button.trigger('year.general', [picker.find('.select-year table')]);
                }
            });

            return $(this);
        }
    });

    var table = (() => {
        return {
            skin: () => `
                <style>
                    .datetime-picker-default-skin{position:absolute;overflow:visible;width:340px;-webkit-border-radius:3px;border-radius:3px;border-top:1px solid #ddd;z-index:2;top:0;left:0;visibility:hidden;}.datetime-picker-default-skin.on{visibility:visible;}.datetime-picker-default-skin.on .datetime-picker-group{opacity:1;visibility:visible;-moz-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);-webkit-transform:translate(0,0);transform:translate(0,0);}.datetime-picker-group{position:relative;visibility:hidden;opacity:0;padding:5px 2px;background:#fff;-moz-transition:.2s linear;-o-transition:.2s linear;-webkit-transition:.2s linear;transition:.2s linear;-moz-transform:translate(0,-5px);-ms-transform:translate(0,-5px);-o-transform:translate(0,-5px);-webkit-transform:translate(0,-5px);transform:translate(0,-5px);}.datetime-picker-group .header{text-align:center;overflow:hidden;}.datetime-picker-group .header .dtp-left,.datetime-picker-group .header .dtp-right{width:30px;height:30px;line-height:30px;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;font-weight:bold;color:#444;text-align:center;display:block;margin:0 auto;}.datetime-picker-group .header .dtp-left:hover,.datetime-picker-group .header .dtp-right:hover{background:#eee;}.datetime-picker-group .header .year{height:30px;line-height:30px;overflow:hidden;font-size:1.4rem;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;font-weight:bold;color:#444;}.datetime-picker-group .header .year:hover{background:#eee;}.datetime-picker-group table{width:100%;border:none;padding:0;margin:0;}.datetime-picker-group table td,.datetime-picker-group table th{text-align:center;height:40px;line-height:40px;font-size:1.1rem;padding:3px 0;}.datetime-picker-group table td a{color:#444;display:block;-moz-border-radius:50%;-webkit-border-radius:50%;border-radius:50%;width:40px;max-width:14.28571429%;margin:0 auto;border:1px solid transparent;}.datetime-picker-group table td a:hover{background:#eee;}.datetime-picker-group table td.on a{background:#0090ff;color:#fff;}.datetime-picker-group table td.not-active a{background:transparent !important;color:#ddd !important;cursor:default;}.datetime-picker-group table td.graw a{color:#999;}.datetime-picker-group .select-month td,.datetime-picker-group .select-year td{height:70px;line-height:70px;}.datetime-picker-group .select-month td a,.datetime-picker-group .select-year td a{width:70px;}.datetime-picker-group .select-year tr:nth-child(2) td:first-child a{color:#999;}.datetime-picker-group .select-year tr:last-child td:last-child a{color:#999;}
                </style>
            `.trim(),

            template: ((options = {}) => {
                return {
                    tr: () => {
                        return $.trim(`<tr class="datetime-tr"></tr>`);
                    },
                    td: (x) => {
                        return `<td><a href="javascript:void(0);">${x}</a></td>`;
                    },
                    //td: (sources = [], callback) => {
                    //    return $.trim(`
                    //    <tr class="datetime-tr">
                    //        ${sources.map((x, index) => $.trim(`
                    //            <td><a href="javascript:void(0);">${x}</a></td>
                    //        `)).join('')}
                    //    </tr>`);
                    //},

                    main: $.trim(`
                        <div class="${options.className || 'datetime-picker-default-skin'}">
                          <div class="datetime-picker-group">
                            <div class="select-year" style="display:none;">
                                <table>
                                    <tr class="header">
                                        <th><a href="javascript:void(0);" class="booticon dtp-left booticon-left"></a></th>
                                        <th colspan="2"><a href="javascript:void(0);"><div class="year"></div></a></th>
                                        <th><a href="javascript:void(0);" class="booticon dtp-right booticon-right"></a></th>
                                    </tr>
                                </table>
                            </div>
                            <div class="select-month" style="display: none;">
                                <table>
                                    <tr class="header">
                                        <th><a href="javascript:void(0);" class="booticon dtp-left booticon-left"></a></th>
                                        <th colspan="2"><a href="javascript:void(0);"><div class="year"></div></a></th>
                                        <th><a href="javascript:void(0);" class="booticon dtp-right booticon-right"></a></th>
                                    </tr>
                                </table>
                            </div>
                            <div class="select-date">
                                <table>
                                    <tr class="header">
                                        <th><a href="javascript:void(0);" class="booticon dtp-left booticon-left"></a></th>
                                        <th colspan="5"><a href="javascript:void(0);"><div class="year"></div></a></th>
                                        <th><a href="javascript:void(0);" class="booticon dtp-right booticon-right"></a></th>
                                    </tr>
                                    <tr>
                                        <th>日</th>
                                        <th>一</th>
                                        <th>二</th>
                                        <th>三</th>
                                        <th>四</th>
                                        <th>五</th>
                                        <th>六</th>
                                    </tr>
                                </table>
                            </div>
                        </div>
                    `)
                };
            })
        };
    })();
    let skin = table.skin();

    //优先添加在head，其次是body
    $(document).find('head,body').first().append(skin);

    return 0;
})(window.$, window, document);
